开启Web站点的http2协议
目前国内许多主流的站点都开始开启了H2协议,http2协议的优势不言而喻,能加快网络传输效率,提升Web服务的访问效率。 那么如何开启http2协议呢,本文就以 Nginx 搭建的站点为例,详细说一下怎么一步步实现支持H2协议的 Web站点。
相关背景
在当前无论是国内还是国外,相当多的主流网站或APP都开始支持HTTP2协议了。 以下测试了淘宝、抖音、github三家站点,它们都开启了HTTP2协议了。
目前 客户端浏览器对 H2协议的支持情况怎么样呢?
从上图可以看出,除了IE11以下的浏览器不支持 Http2 协议,几乎所有的浏览器都支持了,将近 97% 的支持率说明没有什么兼容性问题了。
H2协议简介
什么是http2协议?
http/2 is a replacement for how http is expressed “on the wire.” It is not a ground-up rewrite of the protocol; http methods, status codes and semantics are the same, and it should be possible to use the same APIs as http/1.x (possibly with some small additions) to represent the protocol.
从官网的描述中,我们可以看出:
- 对1.x协议语意的完全兼容
2.0协议是在1.x基础上的升级而不是重写,1.x协议的方法,状态及api在2.0协议里是一样的
The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.
- 主要目标是提升性能
让终端用户使用网络服务,访问网络资源,没有那么高的延迟,能及时给出请求的响应内容,优化性能。 在一个TCP链接中,就能够完成终端和站点之间的通信。
H2优化的内容有很多,我们就不一一展开了,文末有相关的链接,感兴趣的话可以点开细读。
- 二进制分帧(Binary Format)设计
- 多路复用 (Multiplexing) / 连接共享
- 头部压缩(Header Compression)
- 服务端推送(Server Push)
- 。。。。。。
接下来我们进入开启http2协议的流程中。
整体的流程
必备的条件
开启H2协议,需要一下必备条件:
- 先有个域名(需要购买了,有很多便宜的几块钱一年的)
- 获得 SSL 证书(如何获得下面介绍)
- Nginx的版本高于 1.9.5(其它Web服务器软件如Apache,需要自行查看一下)
- 开启相关的 Nginx 的模块 和 配置
整体流程
整个流程如下:
- 先获得 SSL 证书
- 使用 SSL证书,开启 HTTPS协议
- 配置 H2 协议
- 重新载入配置,启动 Web server
- 测试效果
获得SSL证书
如何获得 SSL 证书呢?
有多种方式,看个人的需求。如果是工作上的Web服务,有真实的消费用户,那还是购买正规的SSL证书比较好。 SSL证书的种类也是多种多样的,当然价格越高支持的特性越多,提供的安全性会更好些。以下是国内某云厂商提供的各种 SSL 证书的规格说明,用以满足不同场景下的业务需求。
本文的目的是研究和学习,咱们就申请一个免费的 SSL 证书,来做一下试验。 获得免费证书的途径也有很多的,许多国内外的云厂家(阿里、腾讯、华为、亚马逊等)都提供免费的SSL证书的。 在文末的链接中,提供了三个获得免费SSL证书的网址,需要的小伙伴们自取。
一般在申请的过程中,需要填写一下您的域名、个人联系方式,很简单的。
填写完成后,大约 2 ~ 3 分钟后,就会收到证书通知,产生下面的一条记录。 展示是免费的SSL证书,到期时间,并提供证书的下载入口。
我们点击“下载”,选择 Nginx 格式的证书文件。
我们将下载后的证书文件保存到本地磁盘,其中包括证书以及秘钥两个文件。
接下来,我们将证书文件上传到服务器的 Nginx 目录下面
上传SSL证书
将本地的证书上传到服务器有多种方式,包括rz、FTP、SFTP等等,我们这里使用 rz 上传。 使用 rz
上传前,要确保先安装了 lrzsz
这个工具。 lrzsz 这个工具专门用于远程传输文件的,其中 rz 是从本地上传文件到服务器, sz 是从远程服务下载文件到本地。如果本地使用的是 苹果Mac系统的电脑,远程服务器是 Linux 系统,Shell 用的是 iTerm2,可以参照下面的方式配置一下 rz 的环境:
配置 rz、sz上传下载
- 在远程服务器(centos)上安装lrzsz:
yum install lrzsz
- 在本地的Mac 系统中安装 lrzsz工具:
brew install lrzsz
- 按照下图所示,设置一下iTerm2 的触发器,目的是在接收或发送文件时能和系统的文件管理器交互
具体填写的内容:
Regular Expression | Action | Parameters |
---|---|---|
\*\*B0100 | Run Silent Coprocess | /usr/local/bin/iterm2-send-zmodem.sh |
\*\*B00000000000000 | Run Silent Coprocess | /usr/local/bin/iterm2-recv-zmodem.sh |
这样当我们在 iTerm2 的 shell 中执行 rz
上传命令时,就会弹出系统的文件管理窗体了,就可以选择要上传的证书文件了。
关于 iterm2-send-zmodem.sh 和 iterm2-recv-zmodem.sh 两个 shell 脚本的文件内容,需要手动创建到指定的
/usr/local/bin
目录下
iterm2-send-zmodem.sh
,通知 iTerm2 在 发送文件时,弹出“选择要发送文件”的系统窗口
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
/usr/local/bin/sz "$FILE" -e -b
sleep 1
echo
echo \# Received $FILE
fi
#!/bin/bash
# iterm2-send-zmodem.sh 文件的内容:
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=`osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
else
FILE=`osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose file with prompt "Choose a file to send"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"`
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
/usr/local/bin/sz "$FILE" -e -b
sleep 1
echo
echo \# Received $FILE
fi
iterm2-recv-zmodem.sh
,通知 iTerm2 在接收文件时,弹出“选择要接收的目录”的系统窗口
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
cd "$FILE"
/usr/local/bin/rz -E -e -b --bufsize 4096
sleep 1
echo
echo
echo \# Sent \-\> $FILE
fi
#!/bin/bash
# iterm2-recv-zmodem.sh 文件的内容:
osascript -e 'tell application "iTerm2" to version' > /dev/null 2>&1 && NAME=iTerm2 || NAME=iTerm
if [[ $NAME = "iTerm" ]]; then
FILE=$(osascript -e 'tell application "iTerm" to activate' -e 'tell application "iTerm" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
else
FILE=$(osascript -e 'tell application "iTerm2" to activate' -e 'tell application "iTerm2" to set thefile to choose folder with prompt "Choose a folder to place received files in"' -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")")
fi
if [[ $FILE = "" ]]; then
echo Cancelled.
# Send ZModem cancel
echo -e \\x18\\x18\\x18\\x18\\x18
sleep 1
echo
echo \# Cancelled transfer
else
cd "$FILE"
/usr/local/bin/rz -E -e -b --bufsize 4096
sleep 1
echo
echo
echo \# Sent \-\> $FILE
fi
上传到服务器
我们登录到远程服务器,进入到Nginx目录下面。
- 创建一个 cert 目录,用于存放我们刚才下载到本地的 SSL 证书
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz
# 进入到Nginx的配置目录
cd /etc/nginx
# 创建 cert 目录
mkdir cert
# 进入到 cert 目录
cd cert
# 在服务器上执行 rz 命令,上传 SSL 证书文件
rz
如上图所示,这样输入 rz
命令就能调出本地的 选择文件发送
的系统窗体了。 我们选择好SSL证书文件后,就会上传到服务器的指定目录(/etc/nginx/cert
)下了。 接下来,我们开始配置Nginx 文件。
配置SSL证书
打开 Nginx的配置文件:
vi nginx.conf
vi nginx.conf
修改如下的配置,主要是配置一下证书的路径,以及域名,监听的端口号。 默认情况下,可能有防火墙的策略,需要打开 443端口的通道,以保证外部的 https请求能进入。
server {
#HTTPS的默认访问端口443。
#如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
listen 443 ssl;
#填写证书绑定的域名
server_name mawen.tech;
#填写证书文件名称
ssl_certificate cert/mawen.tech.pem;
#填写证书私钥文件名称
ssl_certificate_key cert/mawen.tech.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
}
server {
#HTTPS的默认访问端口443。
#如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
listen 443 ssl;
#填写证书绑定的域名
server_name mawen.tech;
#填写证书文件名称
ssl_certificate cert/mawen.tech.pem;
#填写证书私钥文件名称
ssl_certificate_key cert/mawen.tech.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
}
修改完毕后,执行:wq
保持一下配置nginx配置文件,重新加载一个配置
nginx -s reload
nginx -s reload
刷新浏览,可以看到已经是 https 协议的地址了。
我们可以更进一步,当访问 http 的地址时,默认转发到 https 协议的地址中,以此来保证站点的内容安全性。
server {
listen 80;
#填写证书绑定的域名
server_name mawen.tech;
#将所有HTTP请求通过rewrite指令重定向到HTTPS。
rewrite ^(.*)$ https://$host$1;
location / {
index index.html index.htm;
}
}
server {
listen 80;
#填写证书绑定的域名
server_name mawen.tech;
#将所有HTTP请求通过rewrite指令重定向到HTTPS。
rewrite ^(.*)$ https://$host$1;
location / {
index index.html index.htm;
}
}
nginx.conf文件中会存在两个server {}代码段,一个是 80 端口的http请求模块,另一个是 443 端口的 https 请求模块,我们要保证 80 端口的server 代码块 放在 443 端口号的下面。 这样http 到 https的转发请求,才能正常跳转过去。
开启H2协议
开启 http2协议就非常简单了,甚至在新版本的Nginx 中都会默认开启 H2的。 只要在 listen 字段后面,增加 http2
的设置即可。
server {
# 对应 IP4
listen 443 ssl http2;
# 对应 IP6
listen [::]:443 ssl http2;
}
server {
# 对应 IP4
listen 443 ssl http2;
# 对应 IP6
listen [::]:443 ssl http2;
}
这里会有两个 监听,一个对应 IP4的网络地址,另一个对应 IP6的地址。 修改完保存一下,重新加载 Nginx的配置。
nginx -s reload
nginx -s reload
验证一下效果:
如上图所示,第二请求的协议地址已经变成h2
了,说明我们的修改生效了。 关于Nginx的完整配置,放在文末最后的链接中了,有需要的小伙伴可以查看。
总结
本文主要讲解了如何开启站点的 http2协议,这里的关键是先要支持 https协议,因为 http2时强依赖 https的,没办法直接在 http协议中开启 H2。 所以,需要先拥有SSL证书,配置好 https协议后,才能进行开启 http2协议。 与此同时,我们也简要介绍了 http2协议的优势,如何申请SSL证书,如何上传证书文件以及修改Nginx的配置等。
相关链接
- https://zhuanlan.zhihu.com/p/89471776 (http2的介绍)
- https://yundun.console.aliyun.com/?&p=cas#/certExtend/free (免费的SSL证书 1)
- https://freessl.org/ (免费的SSL证书 2)
- https://www.joyssl.com/certificate/select/free.html?nid=7 (免费的SSL证书 3)
- https://github.com/ancai/blog-code/blob/main/2022/00-19-http2-nginx/nginx.conf (完整的Nginx配置)